return 1;
}
-/*
- * Local timer interrupt handler.
- * Here the programmable, accurate timers are executed.
- */
-inline void smp_local_timer_interrupt(struct pt_regs *regs)
-{
- do_ac_timer();
-}
-
-/*
- * Local APIC timer interrupt. This is the most natural way for doing
- * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesnt support APIC timers]
- *
- * [ if a single-CPU system runs an SMP kernel then we call the local
- * interrupt as well. Thus we cannot inline the local irq ... ]
- */
unsigned int apic_timer_irqs [NR_CPUS];
void smp_apic_timer_interrupt(struct pt_regs * regs)
{
int cpu = smp_processor_id();
-#ifndef NDEBUG
- u32 cc_start, cc_end;
- rdtscl(cc_start);
-#endif
- /*
- * the NMI deadlock-detector uses this.
- */
- apic_timer_irqs[cpu]++;
-
- /*
- * NOTE! We'd better ACK the irq immediately, because timer handling can
- * be slow. XXX is this save?
- */
ack_APIC_irq();
- /* call the local handler */
- irq_enter(cpu, 0);
+ apic_timer_irqs[cpu]++;
perfc_incrc(apic_timer);
- smp_local_timer_interrupt(regs);
- irq_exit(cpu, 0);
- if (softirq_pending(cpu))
- do_softirq();
-
-#ifndef NDEBUG
- rdtscl(cc_end);
- if ( (cc_end - cc_start) > (cpu_khz * 100) )
- printk("APIC Long ISR on CPU=%02d %08X -> %08X\n",cpu,cc_start,cc_end);
-#endif
+ __cpu_raise_softirq(cpu, AC_TIMER_SOFTIRQ);
}
/*
desc->handler->end(irq);
spin_unlock(&desc->lock);
- if (softirq_pending(cpu))
- do_softirq();
-
rdtscl(cc_end);
if ( !action || (!(action->flags & SA_NOPROFILE)) )
static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
#define FLUSH_ALL 0xffffffff
-asmlinkage void smp_invalidate_interrupt (void)
+asmlinkage void smp_invalidate_interrupt(void)
{
- unsigned long cpu = smp_processor_id();
-
- if (!test_bit(cpu, &flush_cpumask))
- return;
-
- local_flush_tlb();
-
ack_APIC_irq();
- clear_bit(cpu, &flush_cpumask);
+ if (test_and_clear_bit(smp_processor_id(), &flush_cpumask))
+ local_flush_tlb();
}
void flush_tlb_others(unsigned long cpumask)
/* Rough hack to allow accurate timers to sort-of-work with no APIC. */
if ( do_timer_lists_from_pit )
- do_ac_timer();
+ __cpu_raise_softirq(smp_processor_id(), AC_TIMER_SOFTIRQ);
}
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0,
}
-void do_ac_timer(void)
+static void ac_timer_softirq_action(struct softirq_action *a)
{
int cpu = smp_processor_id();
- unsigned long flags;
struct ac_timer *t, **heap;
- s_time_t diff, now = NOW();
- long max;
-
- spin_lock_irqsave(&ac_timers[cpu].lock, flags);
-
- do_timer_again:
- TRC(printk("ACT [%02d] do(): now=%lld\n", cpu, NOW()));
-
- heap = ac_timers[cpu].heap;
-
- while ( (GET_HEAP_SIZE(heap) != 0) &&
- ((t = heap[1])->expires < (NOW() + TIMER_SLOP)) )
- {
- remove_entry(heap, t);
-
- /* Do some stats collection. */
- diff = (now - t->expires);
- if ( diff > 0x7fffffff )
- diff = 0x7fffffff; /* THIS IS BAD! */
- max = perfc_valuea(ac_timer_max, cpu);
- if ( diff > max )
- perfc_seta(ac_timer_max, cpu, diff);
-
- spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
- if ( t->function != NULL )
- t->function(t->data);
- spin_lock_irqsave(&ac_timers[cpu].lock, flags);
-
- /* Heap may have grown while the lock was released. */
- heap = ac_timers[cpu].heap;
- }
-
- if ( GET_HEAP_SIZE(heap) != 0 )
- {
- if ( !reprogram_ac_timer(heap[1]->expires) )
- goto do_timer_again;
- }
- else
- {
- reprogram_ac_timer(0);
- }
-
- spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
- TRC(printk("ACT [%02d] do(): end\n", cpu));
-}
-
-
-static void ac_timer_softirq_action(struct softirq_action *a)
-{
- int cpu = smp_processor_id();
- unsigned long flags;
- struct ac_timer *t;
- int process_timer_list = 0;
+ s_time_t now;
- spin_lock_irqsave(&ac_timers[cpu].lock, flags);
+ spin_lock_irq(&ac_timers[cpu].lock);
- if ( GET_HEAP_SIZE(ac_timers[cpu].heap) != 0 )
- {
- /*
- * Reprogram timer with earliest deadline. If that has already passed
- * then we will process the timer list as soon as we release the lock.
- */
- t = ac_timers[cpu].heap[1];
- if ( (t->expires < (NOW() + TIMER_SLOP)) ||
- !reprogram_ac_timer(t->expires) )
- process_timer_list = 1;
- }
- else
- {
- /* No deadline to program the timer with.*/
- reprogram_ac_timer((s_time_t)0);
+ do {
+ heap = ac_timers[cpu].heap;
+ now = NOW();
+
+ while ( (GET_HEAP_SIZE(heap) != 0) &&
+ ((t = heap[1])->expires < (now + TIMER_SLOP)) )
+ {
+ remove_entry(heap, t);
+
+ spin_unlock_irq(&ac_timers[cpu].lock);
+ if ( t->function != NULL )
+ t->function(t->data);
+ spin_lock_irq(&ac_timers[cpu].lock);
+
+ /* Heap may have grown while the lock was released. */
+ heap = ac_timers[cpu].heap;
+ }
}
+ while ( !reprogram_ac_timer(GET_HEAP_SIZE(heap) ? heap[1]->expires : 0) );
- spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
-
- if ( process_timer_list )
- do_ac_timer();
+ spin_unlock_irq(&ac_timers[cpu].lock);
}
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sched.h>
-//#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
-//#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/tqueue.h>
int cpu = smp_processor_id();
struct softirq_action *h;
__u32 pending;
- long flags;
- if (in_interrupt())
- return;
-
- local_irq_save(flags);
-
- pending = xchg(&softirq_pending(cpu), 0);
- if ( !pending ) goto out;
+ if ( in_interrupt() )
+ BUG();
local_bh_disable();
- do {
- local_irq_enable();
-
+ while ( (pending = xchg(&softirq_pending(cpu), 0)) != 0 )
+ {
h = softirq_vec;
-
- do {
+ while ( pending )
+ {
if (pending & 1)
h->action(h);
h++;
pending >>= 1;
- } while (pending);
-
- local_irq_disable();
-
- pending = xchg(&softirq_pending(cpu), 0);
- } while ( pending );
+ }
+ }
__local_bh_enable();
-
-out:
- local_irq_restore(flags);
}
-/*
- * This function must run with irq disabled!
- */
inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr)
{
__cpu_raise_softirq(cpu, nr);
-
#ifdef CONFIG_SMP
if ( cpu != smp_processor_id() )
smp_send_event_check_cpu(cpu);
void raise_softirq(unsigned int nr)
{
- long flags;
-
- local_irq_save(flags);
cpu_raise_softirq(smp_processor_id(), nr);
- local_irq_restore(flags);
}
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
void tasklet_kill(struct tasklet_struct *t)
{
if (in_interrupt())
- printk("Attempt to kill tasklet from interrupt\n");
+ BUG();
while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
while (test_bit(TASKLET_STATE_SCHED, &t->state))
do_softirq();
# define dprintk(x)
#endif
-/* Start of Xen additions XXX */
#include <asm/byteorder.h>
#include <xeno/interrupt.h>
-#define TRY_TASKLET
-/* End of Xen additions XXX */
/*------------------------------------------------------------------------------
* D E F I N E S
int aac_sa_init(struct aac_dev *dev, unsigned long devNumber);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
-#ifdef TRY_TASKLET
-extern struct tasklet_struct aac_command_tasklet;
-void aac_command_thread(unsigned long data);
-#else
-int aac_command_thread(struct aac_dev * dev);
-#endif
+void aac_command_thread(struct aac_dev * dev);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
int fib_adapter_complete(struct fib * fibptr, unsigned short size);
struct aac_driver_ident* aac_get_driver_ident(int devtype);
if (wait) {
spin_unlock_irqrestore(&fibptr->event_lock, flags);
-#if 0
- down(&fibptr->event_wait);
- if(fibptr->done == 0)
- BUG();
-#endif
-#ifdef TRY_TASKLET
- while (!fibptr->done) {
- tasklet_schedule(&aac_command_tasklet);
- do_softirq(); /* force execution */
- }
-#else
- while (!fibptr->done) {
- mdelay(100);
- aac_command_thread(dev);
- }
-#endif
-
-
+ while (!fibptr->done)
+ aac_command_thread(dev);
if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
return -ETIMEDOUT;
else
* until the queue is empty. When the queue is empty it will wait for
* more FIBs.
*/
-#ifndef TRY_TASKLET
-int aac_command_thread(struct aac_dev * dev)
-{
-#else
-DECLARE_TASKLET_DISABLED(aac_command_tasklet, aac_command_thread, 0);
-void aac_command_thread(unsigned long data)
-#define return(_x) return
+void aac_command_thread(struct aac_dev * dev)
{
- struct aac_dev *dev = (struct aac_dev *)data;
-#endif
struct hw_fib *hw_fib, *hw_newfib;
struct fib *fib, *newfib;
struct aac_queue_block *queues = dev->queues;
struct aac_fib_context *fibctx;
unsigned long flags;
-#if 0
- DECLARE_WAITQUEUE(wait, current);
-#endif
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+ spin_lock_irqsave(&lock, flags);
- /*
- * We can only have one thread per adapter for AIF's.
- */
- if (dev->aif_thread)
- return(-EINVAL);
-#if 0
- /*
- * Set up the name that will appear in 'ps'
- * stored in task_struct.comm[16].
- */
- sprintf(current->comm, "aacraid");
- daemonize();
-#endif
- /*
- * Let the DPC know it has a place to send the AIF's to.
- */
- dev->aif_thread = 1;
-#if 0
- add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- dprintk ((KERN_INFO "aac_command_thread start\n"));
- while(1)
-#endif
{
- spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+ spin_lock(queues->queue[HostNormCmdQueue].lock);
while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
struct list_head *entry;
struct aac_aifcmd * aifcmd;
-#if 0
- set_current_state(TASK_RUNNING);
-#endif
-
entry = queues->queue[HostNormCmdQueue].cmdq.next;
list_del(entry);
- spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+ spin_unlock(queues->queue[HostNormCmdQueue].lock);
fib = list_entry(entry, struct fib, fiblink);
/*
* We will process the FIB here or pass it to a
*/
list_add_tail(&newfib->fiblink, &fibctx->fib_list);
fibctx->count++;
-#if 0
- /*
- * Set the event to wake up the
- * thread that will waiting.
- */
- up(&fibctx->wait_sem);
-#endif
} else {
printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
if(newfib)
fib_adapter_complete(fib, sizeof(u32));
spin_unlock_irqrestore(&dev->fib_lock, flagv);
}
- spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+ spin_lock(queues->queue[HostNormCmdQueue].lock);
kfree(fib);
}
/*
* There are no more AIF's
*/
- spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
-#if 0
- schedule();
-
- if(signal_pending(current))
- break;
- set_current_state(TASK_INTERRUPTIBLE);
-#endif
+ spin_unlock(queues->queue[HostNormCmdQueue].lock);
}
-#if 0
- remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
- dev->aif_thread = 0;
- complete_and_exit(&dev->aif_completion, 0);
-#else
- mdelay(50);
- dev->aif_thread = 0;
-#endif
+
+ spin_unlock_irqrestore(&lock, flags);
}
if (aac_init_adapter(dev) == NULL)
return -1;
-#ifdef TRY_TASKLET
- aac_command_tasklet.data = (unsigned long)dev;
- tasklet_enable(&aac_command_tasklet);
-#else
- /*
- * Start any kernel threads needed
- */
- dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
- if(dev->thread_pid < 0)
- {
- printk(KERN_ERR "aacraid: Unable to create rx thread.\n");
- return -1;
- }
-#endif
/*
* Tell the adapter that all is configured, and it can start
* accepting requests
if (next_dev) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
tasklet_schedule(&ahc->platform_data->runq_tasklet);
- do_softirq();
#else
ahc_runq_tasklet((unsigned long)ahc);
#endif
scsi_unblock_requests(ahc->platform_data->host);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
tasklet_schedule(&ahc->platform_data->runq_tasklet);
- do_softirq();
#else
ahc_runq_tasklet((unsigned long)ahc);
#endif
if it hasn't been done already. This is not the correct behaviour
in xen ... hmm .. how to fix? */
while(wait) {
+ do_softirq(); /* XXX KAF: this is safe, and necessary!! */
udelay(500);
usecs += 500;
if(usecs > 1000000) {
#define cpu_bh_disable(cpu) \
do { local_bh_count(cpu)++; barrier(); } while (0)
-#define local_bh_disable() cpu_bh_disable(smp_processor_id())
-#define __local_bh_enable() __cpu_bh_enable(smp_processor_id())
+#define local_bh_disable() cpu_bh_disable(smp_processor_id())
+#define __local_bh_enable() __cpu_bh_enable(smp_processor_id())
+#define local_bh_enable() __local_bh_enable()
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
-/*
- * NOTE: this assembly code assumes:
- *
- * (char *)&local_bh_count - 8 == (char *)&softirq_pending
- *
- * If you change the offsets in irq_stat then you have to
- * update this code as well.
- */
-#define local_bh_enable() \
-do { \
- unsigned int *ptr = &local_bh_count(smp_processor_id()); \
- \
- barrier(); \
- if (!--*ptr) \
- __asm__ __volatile__ ( \
- "cmpl $0, -8(%0);" \
- "jnz 2f;" \
- "1:;" \
- \
- ".section .text.lock,\"ax\";" \
- "2: pushl %%eax; pushl %%ecx; pushl %%edx;" \
- "call %c1;" \
- "popl %%edx; popl %%ecx; popl %%eax;" \
- "jmp 1b;" \
- ".previous;" \
- \
- : /* no output */ \
- : "r" (ptr), "i" (do_softirq) \
- /* no registers clobbered */ ); \
-} while (0)
-
#endif /* __ASM_SOFTIRQ_H */
/* interface used by programmable timer, implemented hardware dependent */
extern int reprogram_ac_timer(s_time_t timeout);
-extern void do_ac_timer(void);
#endif /* _AC_TIMER_H_ */
extern int dev_change_flags(struct net_device *, unsigned);
extern void dev_init(void);
-extern int netdev_nit;
-
-/* Post buffer to the network code from _non interrupt_ context.
- * see net/core/dev.c for netif_rx description.
- */
-static inline int netif_rx_ni(struct sk_buff *skb)
-{
- int err = netif_rx(skb);
- if (softirq_pending(smp_processor_id()))
- do_softirq();
- return err;
-}
-
extern int netdev_finish_unregister(struct net_device *dev);
static inline void dev_put(struct net_device *dev)